pub(crate) const PXD_TYPE_SECT: u64 = 1;
pub(crate) const PXD_TABLE_BIT: u64 = 1 << 1;
pub(crate) const PXD_TYPE_TABLE: u64 = 3;
pub(crate) const PXD_TABLE_PXN: u64 = 1 << 59;
pub(crate) const PXD_TABLE_UXN: u64 = 1 << 60;

const PTE_VALID: u64 = 1;
const PTE_TYPE_PAGE: u64 = 3;
const PTE_USER: u64 = 1 << 6; // AP[1]
const PTE_RDONLY: u64 = 1 << 7; // AP[2]
const PTE_SHARED: u64 = 3 << 8; // SH[1:0], inner shareable
const PTE_AF: u64 = 1 << 10; // Access Flag
const PTE_NG: u64 = 1 << 11; // nG
#[allow(unused)]
const PTE_GP: u64 = 1 << 50; // BTI guarded
const PTE_DBM: u64 = 1 << 51; // Dirty Bit Management
const PTE_CONT: u64 = 1 << 52; // Contiguous range
const PTE_PXN: u64 = 1 << 53; // Privileged XN
const PTE_UXN: u64 = 1 << 54; // User XN

// software define
const PTE_WRITE: u64 = PTE_DBM;
const PTE_PROT_NONE: u64 = 1 << 58;

const _PROT_DEFAULT: u64 = PTE_TYPE_PAGE | PTE_AF | PTE_SHARED;
const _PROT_SECT_DEFAULT: u64 = PXD_TYPE_SECT | PTE_AF | PTE_SHARED;

const PTE_MAYBE_NG: u64 = 0;
const PXD_MAYBE_NG: u64 = 0;

const PROT_DEFAULT: u64 = _PROT_DEFAULT | PTE_MAYBE_NG;
const PROT_SECT_DEFAULT: u64 = _PROT_SECT_DEFAULT | PXD_MAYBE_NG;

#[allow(non_upper_case_globals, unused)]
const MT_DEVICE_nGnRnE: usize = 0;
#[allow(non_upper_case_globals)]
const MT_DEVICE_nGnRE: usize = 1;
#[allow(unused)]
const MT_DEVICE_GRE: usize = 2;
const MT_NORMAL_NC: usize = 3;
const MT_NORMAL: usize = 4;
#[allow(unused)]
const MT_NORMAL_WT: usize = 5;

const fn pte_attrindx(idx: usize) -> u64 {
    (idx << 2) as u64
}

#[allow(non_upper_case_globals)]
const PROT_DEVICE_nGnRnE: u64 =
    PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | pte_attrindx(MT_DEVICE_nGnRE);
#[allow(non_upper_case_globals)]
const PROT_DEVICE_nGnRE: u64 =
    PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | pte_attrindx(MT_DEVICE_nGnRE);
const PROT_NORMAL_NC: u64 =
    PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | pte_attrindx(MT_NORMAL_NC);
const PROT_NORMAL: u64 = PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_WRITE | pte_attrindx(MT_NORMAL);

#[allow(non_upper_case_globals)]
const PROT_SECT_DEVICE_nGnRE: u64 =
    PROT_SECT_DEFAULT | PTE_PXN | PTE_UXN | pte_attrindx(MT_DEVICE_nGnRE);
const PROT_SECT_NORMAL: u64 = PROT_SECT_DEFAULT | PTE_PXN | PTE_UXN | pte_attrindx(MT_NORMAL);
const PROT_SECT_NORMAL_EXEC: u64 = PROT_SECT_DEFAULT | PTE_UXN | pte_attrindx(MT_NORMAL);

bitflags::bitflags! {
    pub struct KernelPageProt: u64 {
        const DEVICE_nGnRnE = PROT_DEVICE_nGnRnE;
        const DEVICE_nGnRE = PROT_DEVICE_nGnRE;
        const NORMAL_NC = PROT_NORMAL_NC;
        const NORMAL = PROT_NORMAL;

        const SECT_DEVICE_nGnRE = PROT_SECT_DEVICE_nGnRE;
        const SECT_NORMAL = PROT_SECT_NORMAL;
        const SECT_NORMAL_EXEC = PROT_SECT_NORMAL_EXEC;
    }
}

const _PAGE_DEFAULT: u64 = _PROT_DEFAULT | pte_attrindx(MT_NORMAL);

bitflags::bitflags! {
    pub struct UserPageProt: u64 {
        const PAGE_KERNEL = PROT_NORMAL;
        const PAGE_KERNEL_RO = (PROT_NORMAL & !PTE_WRITE) | PTE_RDONLY;
        const PAGE_KERNEL_ROX = (PROT_NORMAL & !(PTE_WRITE | PTE_PXN)) | PTE_RDONLY;
        const PAGE_KERNEL_EXEC = PROT_NORMAL & !PTE_PXN;
        const PAGE_KERNEL_EXEC_CONT = (PROT_NORMAL & !PTE_PXN) | PTE_CONT;

        const PAGE_NONE = ((_PAGE_DEFAULT) & !PTE_VALID) | PTE_PROT_NONE | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN;
        const PAGE_SHARED = _PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE;
        const PAGE_SHARED_EXEC = _PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE;
        const PAGE_READONLY = _PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN;
        const PAGE_READONLY_EXEC = _PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN;
        const PAGE_EXECONLY = _PAGE_DEFAULT | PTE_RDONLY | PTE_NG | PTE_PXN;
    }
}
